using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using StudentVideo.Common.Attributes;
using StudentVideo.Common.Constants;
using StudentVideo.Common.Exceptions;
using StudentVideo.Common.Models;
using StudentVideo.Data;
using StudentVideo.Data.Entities;
using StudentVideo.Helper;
using StudentVideo.Shared.Dtos.Student;
using StudentVideo.Shared.Enums;
using StudentVideo.Utils;

namespace StudentVideo.Controllers;

[ApiController]
[Route("api/[controller]/[action]")]
[RoleAuthorize(RoleEnum.Admin)]
public class StudentController(AppDbContext context, IMapper mapper): ControllerBase {
   private readonly AppDbContext _context = context;
   private readonly IMapper _mapper = mapper;

   /// <summary>
   /// 创建
   /// </summary>
   /// <param name="user"></param>
   /// <param name="data"></param>
   [HttpPost]
   public async Task Create([FromCurrentUser] CurrentUser user, [FromBody] StudentCreateRequest data) {
      // 检查是否已存在
      var existe = await _context.Students.AnyAsync(e => e.IdCard == data.IdCard || e.StudentId == data.Id);

      if (existe)
         throw new HttpException(HttpErrorMessage.STUDENTS_EXIST);

      // 生成密码
      var idcard = data.IdCard;
      var last = idcard[^4..];
      var (pwd, salt) = PasswordHasher.HashPassword(last);

      // 根据 idcard 获取部分信息
      int sex = (int)data.Gender;
      var birth = data.Birth;
      if (idcard.Length == 18) {
         // 提取性别
         sex = (int.Parse(idcard[16].ToString()) % 2) + 1;
         // 提取出生日期
         var birthDateString = idcard[6..14];
         var year = birthDateString[..4];
         var month = birthDateString[4..6];
         var day = birthDateString[6..8];

         birth ??= $"{year}-{month}-{day}";
      }

      // 利用入学时间计算毕业时间
      var enrollmentYear = int.Parse(data.Enrollment[..4]);
      var graduationDate = $"{enrollmentYear + 4}-6-15";

      // 使用AutoMapper进行对象映射
      var newData = _mapper.Map<StudentEntity>(data);
      newData.IdCard = data.IdCard;
      newData.Password = pwd;
      newData.Gender = (GenderEnum)sex;
      newData.BirthDate = DateTime.Parse(birth!);
      newData.GraduationDate = DateTime.Parse(graduationDate);
      newData.Salt = salt;
      newData.CreateBy = user.UserId;

      await _context.Students.AddAsync(newData);
      await _context.SaveChangesAsync();

      return;
   }

   /// <summary>
   /// 删除
   /// </summary>
   /// <param name="data"></param>
   [HttpPost]
   public async Task Del([FromBody] StudentDelRequest data) {
      // 状态设置为 未激活
      var student = await _context.Students.FirstOrDefaultAsync(s => s.StudentId == data.Id)
         ?? throw new HttpException(HttpErrorMessage.STUDENTS_NOT_EXIST);

      student.Enable = false;

      await _context.SaveChangesAsync();

      return;
   }

   private readonly QueryMapping<StudentEntity, StudentFindRequest> _studentFindMapping = new QueryMapping<StudentEntity, StudentFindRequest>()
      .AddMapping(d => d.Name, s => s.Name, s => s.StudentId, s => s.Phone)
      .AddMapping(d => d.Sex, s => s.Gender)
      .AddMapping(d => d.Major, s => s.Major, QueryOperator.Contains)
      .AddMapping(d => d.SchoolYear, s => s.Grade)
      .AddMapping(d => d.Semester, s => s.Semester)
      .AddMapping(d => d.CreateTimeBetween, s => s.CreateAt, QueryOperator.Between)
      .AddMapping(d => d.EnrollmentDateBetween, s => s.EnrollmentDate, QueryOperator.Between);

   /// <summary>
   /// 查询
   /// </summary>
   /// <param name="data"></param>
   /// <returns></returns>
   [HttpPost]
   public async Task<StudentFindResult> Find([FromBody] StudentFindRequest data) {
      var q = _context.Students.AsQueryable();
      var query = _studentFindMapping.BuildQuery(q, data);

      var total = await query.CountAsync();

      var students = await query
          .Skip((data.Page.PageCurrent - 1) * data.Page.PageSize)
          .Take(data.Page.PageSize)
          .ToListAsync();

      // 对列表进行转换
      List<StudentFindResultItem> list = [];

      foreach (var value in students) {
         list.Add(_mapper.Map<StudentFindResultItem>(value));
      }

      return new StudentFindResult {
         List = list,
         Page = new() {
            PageCurrent = data.Page.PageCurrent,
            PageSize = data.Page.PageSize,
            Total = total
         }
      };
   }
}
